package com.jianan.mis.service;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import com.jianan.mis.data.dao.OsContractDao;
import com.jianan.mis.data.dao.OsContractFinanceDetailDao;
import com.jianan.mis.data.dao.OsContractMaterialDao;
import com.jianan.mis.data.dao.OsContractPlanDao;
import com.jianan.mis.data.dao.OsContractSurveyDao;
import com.jianan.mis.data.dao.base.PageControl;
import com.jianan.mis.data.domain.Country;
import com.jianan.mis.data.domain.Material;
import com.jianan.mis.data.domain.OsContract;
import com.jianan.mis.data.domain.OsContractFinanceDetail;
import com.jianan.mis.data.domain.OsContractMaterial;
import com.jianan.mis.data.domain.OsContractPlan;
import com.jianan.mis.data.domain.OsContractState;
import com.jianan.mis.data.domain.OsContractSurvey;

public class OsContractServiceImpl implements OsContractService {

	private OsContractDao osContractDao;
	
	private OsContractPlanDao osContractPlanDao;
	
	private OsContractMaterialDao osContractMaterialDao;
	
	private OsContractSurveyDao osContractSurveyDao;
	
	private OsContractFinanceDetailDao osContractFinanceDetailDao;
	
	public void remove(OsContract osContract) {
		osContractDao.remove(osContract);
	}

	public Serializable save(OsContract osContract) {
		return osContractDao.save(osContract);
	}

	public void update(OsContract osContract) {
		osContract.setUpdateDate(new Date());
		osContractDao.saveOrUpdate(osContract);
	}

	public List<OsContract> getAll() {
		return osContractDao.getAll(OsContract.class, "id", true);
	}

	@SuppressWarnings("unchecked")
	public List<OsContract> getByStates(int[] states) {
		Criteria criteria = osContractDao.createCriteria(OsContract.class);
		for(int state : states) {
			criteria.add(Restrictions.eq("State", state));
		}
		return criteria.list();
	}

	public void pageQuery(PageControl pageControl, Map conditions) {
		Criteria criteria = osContractDao.createCriteria(OsContract.class);
		if (conditions.get("studentName") != null) {
			String studentName = (String) conditions.get("studentName");
			criteria.add(Restrictions.like("Name", studentName, MatchMode.ANYWHERE));
		}
		if (conditions.get("countryId") != null) {
			Integer countryId = (Integer) conditions.get("countryId");
			criteria.add(Expression.eq("CountryIntent.id", countryId));
		}
		if (conditions.get("materialmanId") != null) {
			Integer materialmanId = (Integer) conditions.get("materialmanId");
			criteria.add(Expression.eq("Materialman.id", materialmanId));
		}
		if (conditions.get("contractNo") != null) {
			String contractNo = (String) conditions.get("contractNo");
			criteria.add(Restrictions.like("ContractNo", contractNo, MatchMode.ANYWHERE));
		}
		if (conditions.get("visaResult") != null) {
			String visaResult = (String) conditions.get("visaResult");
			criteria.add(Restrictions.eq("VisaResult", visaResult));
		}
		if (conditions.get("onlyConsultantId") != null) {
			Integer onlyConsultantId = (Integer) conditions.get("onlyConsultantId");
			criteria.add(Expression.eq("Consultant.id", onlyConsultantId));
		}
		if (conditions.get("state") != null) {
			Integer state = (Integer) conditions.get("state");
			switch (state) {
			case 0:
				criteria.add(Restrictions.eq("State", OsContractState.SIGNED));
				break;
			case 1:
				criteria.add(Restrictions.eq("State", OsContractState.HANDOVERED));
				break;
			case 2:
				criteria.add(Restrictions.eq("State", OsContractState.MATERIAL_PREPARED));
				break;
			case 3:
				criteria.add(Restrictions.eq("State", OsContractState.SENT));
				break;
			case 4:
				criteria.add(Restrictions.eq("State", OsContractState.VISA_FINISHED));
				break;
			case 5:
				criteria.add(Restrictions.eq("State", OsContractState.FINANCE_FINISHED));
				break;
			case 6:
				criteria.add(Restrictions.eq("State", OsContractState.FINISHED));
				break;
			case 7:
				criteria.add(Restrictions.eq("State", OsContractState.EXPIRED));
				break;
			case 8:
				criteria.add(Restrictions.eq("State", OsContractState.FINANCE_REVOKED));
				break;
			case 9:
				criteria.add(Restrictions.eq("State", OsContractState.REVOKED));
				break;
			}
		}
		if (conditions.get("finishedStates") != null) {
			criteria.add(Restrictions.or(Restrictions.eq("State",
					OsContractState.FINISHED), Restrictions.eq("State",
					OsContractState.REVOKED)));
		}
		if (conditions.get("restrictedStates") != null) {
			Integer[] restrictedStates = (Integer[]) conditions.get("restrictedStates");
			for (Integer restrictedState : restrictedStates) {
				criteria.add(Restrictions.ne("State", restrictedState));
			}
		}
		criteria.addOrder(Order.asc("id"));
		pageControl = osContractDao.pagedQuery(criteria, pageControl);
	}

	public void savePlan(OsContract osContract) {
		// 创建进度表
		OsContractPlan plan = new OsContractPlan();
		plan.setOsContract(osContract);
		plan.setMaterialState(0);
		osContractPlanDao.save(plan);
		
		// 创建材料清单
		Country country = osContract.getCountryIntent();
		Set<Material> materials = country.getMaterials();
		for(Material material : materials) {
			OsContractMaterial osContractMaterial = new OsContractMaterial();
			osContractMaterial.setOsContract(osContract);
			osContractMaterial.setMaterial(material.getName());
			osContractMaterial.setCollected(false);
			osContractMaterial.setTranslated(false);
			osContractMaterialDao.save(osContractMaterial);
		}
	}
	
	public void updatePlan(OsContractPlan osContractPlan) {
		osContractPlanDao.saveOrUpdate(osContractPlan);
	}
	
	public OsContractPlan getPlan(OsContract osContract) {
		return osContractPlanDao.findUniqueBy(OsContractPlan.class, "OsContract.id", osContract.getId());
	}

	public void updateMaterials(OsContract osContract, List<OsContractMaterial> materials) {
		List<OsContractMaterial> oldMaterials = getMaterials(osContract);
		for(OsContractMaterial oldMaterial : oldMaterials) {
			osContractMaterialDao.remove(oldMaterial);
		}
		int total = materials.size();
		int collected = 0;
		int translated = 0;
		for(OsContractMaterial newMaterial : materials) {
			if (newMaterial.isCollected())
				collected++;
			if (newMaterial.isTranslated())
				translated++;
			osContractMaterialDao.save(newMaterial);
		}
		osContract.setCollectRate(new BigDecimal(collected*100/total).setScale(2, BigDecimal.ROUND_HALF_UP));
		osContract.setTranslateRate(new BigDecimal(translated*100/total).setScale(2, BigDecimal.ROUND_HALF_UP));
		osContractDao.saveOrUpdate(osContract);
	}

	@SuppressWarnings("unchecked")
	public List<OsContractMaterial> getMaterials(OsContract osContract) {
		Criteria criteria = osContractMaterialDao
				.createCriteria(OsContractMaterial.class);
		criteria.add(Expression.eq("OsContract.id", osContract.getId()));
		return criteria.list();
	}
	
	public void updateSurveys(OsContract osContract, List<OsContractSurvey> surveys) {
		List<OsContractSurvey> oldSurveys = getSurveys(osContract);
		for(OsContractSurvey oldSurvey : oldSurveys) {
			osContractSurveyDao.remove(oldSurvey);
		}
		for(OsContractSurvey newSurvey : surveys) {
			osContractSurveyDao.save(newSurvey);
		}
	}

	@SuppressWarnings("unchecked")
	public List<OsContractSurvey> getSurveys(OsContract osContract) {
		Criteria criteria = osContractSurveyDao
				.createCriteria(OsContractSurvey.class);
		criteria.add(Expression.eq("OsContract.id", osContract.getId()));
		return criteria.list();
	}
	
	public void updateFinanceDetails(OsContract osContract, List<OsContractFinanceDetail> details) {
		List<OsContractFinanceDetail> oldDetails = getFinanceDetails(osContract);
		for(OsContractFinanceDetail oldDetail : oldDetails) {
			osContractFinanceDetailDao.remove(oldDetail);
		}
		for(OsContractFinanceDetail newDetail : details) {
			osContractFinanceDetailDao.save(newDetail);
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<OsContractFinanceDetail> getFinanceDetails(OsContract osContract) {
		Criteria criteria = osContractFinanceDetailDao
				.createCriteria(OsContractFinanceDetail.class);
		criteria.add(Expression.eq("OsContract.id", osContract.getId()));
		return criteria.list();
	}

	public List getStat(Map conditions) {
		Criteria criteria = osContractDao.createCriteria(OsContract.class);
		if(conditions.get("groupType") != null) {
			Integer groupType = (Integer) conditions.get("groupType");
			ProjectionList projectionList = Projections.projectionList();
			switch(groupType) {
			case 0:
				// 按咨询员
				projectionList.add(Projections.groupProperty("Consultant.id"), "id");
				break;
			case 1:
				// 按中间人
				projectionList.add(Projections.groupProperty("Interman.id"), "id");
				break;
			case 2:
				// 按咨询国家
				projectionList.add(Projections.groupProperty("CountryIntent.id"), "id");
				break;
			case 3:
				// 按材料员
				projectionList.add(Projections.groupProperty("Materialman.id"), "id");
				break;
			case 4:
				// 按机构
				projectionList.add(Projections.groupProperty("Interman.id"), "id");
				break;
			}
			projectionList.add(Projections.rowCount(), "times");
			criteria.setProjection(projectionList);
		} else {
			criteria.setProjection(Projections.count("id")); 
		}
		if (conditions.get("visaResult") != null) {
			Integer visaResult = (Integer) conditions.get("visaResult");
			if (visaResult == 0) {
				criteria.add(Restrictions.eq("VisaResult", "获签"));
			} else if (visaResult == 1) {
				criteria.add(Restrictions.eq("VisaResult", "拒签"));
			}
		}
		if (conditions.get("timeType") != null) {
			Integer timeType = (Integer) conditions.get("timeType");
			Date time = (Date) conditions.get("time");
			if (timeType >= 0) {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(time);
				if (timeType == 0) {
					// 按月份
					calendar.set(Calendar.DATE, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
					criteria.add(Restrictions.ge("SignupDate", calendar.getTime()));
					calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
					criteria.add(Restrictions.le("SignupDate", calendar.getTime()));
				} else if (timeType == 1) {
					// 按年份
					calendar.set(Calendar.MONTH, calendar.getActualMinimum(Calendar.MONTH));
					calendar.set(Calendar.DATE, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
					criteria.add(Restrictions.ge("SignupDate", calendar.getTime()));
					calendar.set(Calendar.MONTH, calendar.getActualMaximum(Calendar.MONTH));
					calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
					criteria.add(Restrictions.le("SignupDate", calendar.getTime()));
				}
			}
		}
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	public void updateExpired() {
		// 查询所有 超过签约时间30天，并且收集率为空或为0 的咨询表
		Criteria criteria = osContractDao.createCriteria(OsContract.class);
		
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DATE, -29);
		criteria.add(Restrictions.lt("SignupDate", calendar.getTime()));
		criteria.add(Restrictions.or(Restrictions.isNull("CollectRate"), Restrictions.eq("CollectRate", new BigDecimal(0))));
		
		List<OsContract> osContracts = criteria.list();
		// 修改状态为过期
		for(OsContract osContract : osContracts) {
			osContract.setState(OsContractState.EXPIRED);
			osContractDao.saveOrUpdate(osContract);
		}
	}

	@SuppressWarnings("unchecked")
	public List<OsContract> getOver20Contracts() {
//		 查询所有 超过签约时间20天，并且收集率为空或为0 的咨询表
		Criteria criteria = osContractDao.createCriteria(OsContract.class);

		criteria.add(Restrictions.ne("State", OsContractState.EXPIRED));
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DATE, -19);
		criteria.add(Restrictions.lt("SignupDate", calendar.getTime()));
		criteria.add(Restrictions.or(Restrictions.isNull("CollectRate"), Restrictions.eq("CollectRate", new BigDecimal(0))));
		
		return criteria.list();
	}

	public boolean checkContractNoExists(String contractNo) {
		if (osContractDao.findUniqueBy(OsContract.class, "ContractNo",
				contractNo) != null)
			return true;
		else
			return false;
	}

	public void setOsContractDao(OsContractDao osContractDao) {
		this.osContractDao = osContractDao;
	}

	public void setOsContractPlanDao(OsContractPlanDao osContractPlanDao) {
		this.osContractPlanDao = osContractPlanDao;
	}

	public void setOsContractMaterialDao(OsContractMaterialDao osContractMaterialDao) {
		this.osContractMaterialDao = osContractMaterialDao;
	}

	public void setOsContractSurveyDao(OsContractSurveyDao osContractSurveyDao) {
		this.osContractSurveyDao = osContractSurveyDao;
	}

	public void setOsContractFinanceDetailDao(
			OsContractFinanceDetailDao osContractFinanceDetailDao) {
		this.osContractFinanceDetailDao = osContractFinanceDetailDao;
	}

}
